package com.i72.governance.service.helper;

import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.i72.governance.service.bean.ServiceConfig;
import com.i72.governance.service.bean.ServiceInfo;
import com.i72.governance.service.bean.ServiceNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class NacosServiceHelper implements ServiceHelper {


    /**
     * 服务治理中间件配置信息
     */
    @Autowired
    private ServiceConfig serviceConfig;

    /**
     * 当前应用名。
     */
    /*
    @Value("${governance.service.serviceName}")
    private String appName;*/

    /**
     * 被订阅的服务列表
     */
    private List<String> subscribeServiceNameList = new ArrayList<>();

    private Map<String, ServiceInfo> serviceInfoMap = new HashMap<>();

    //private List<ServiceInfo> serviceInfos = new ArrayList<>();

    private static Object LOCK = new Object();
    private static boolean updating = false;
    private static NamingService nameService;

    private NamingService getNameService() {
        if (nameService == null) {
            synchronized (LOCK) {
                if (nameService == null) {

                    try {
                        nameService = NamingFactory.createNamingService(serviceConfig.getAddress());
                    } catch (Exception e) {
                        log.error("nacos create error");
                    }
                }
            }
        }
        return nameService;
    }

    @Override
    @PostConstruct  //初始化注解，即使手动注册他依然是有效的
    public void initService() {
        this.getNameService();
    }





    @Override
    public void subscribeService(List<String> serviceNameList) {
        //订阅与监听一体
        if (serviceNameList != null && serviceNameList.size()>0) {
            for (String name : serviceNameList) {
                try {
                    if(this.subscribeServiceNameList.contains(name)){
                        continue; //拒绝重复订阅
                    }
                    //订阅
                    //nameService.getAllInstances(name);

                    //监听
                    nameService.subscribe(name, new NacosEventListener());
                } catch (Exception e) {
                    log.error("nacos subscribe error!");
                }
            }

            //加入订阅列表，去重
            this.subscribeServiceNameList.addAll(serviceNameList);
            this.subscribeServiceNameList = this.subscribeServiceNameList.stream().distinct().collect(Collectors.toList());

        }
    }

    @Override
    public List<ServiceInfo> getAllServiceInfo() {
        return new ArrayList<>(this.serviceInfoMap.values());
    }

    @Override
    public ServiceInfo getServiceInfo(String serviceName) {
        if (this.serviceInfoMap.containsKey(serviceName)) {
            return this.serviceInfoMap.get(serviceName);
        }
        return null;
    }

    @Override
    public boolean addServiceInfo(ServiceInfo serviceInfo) {

        if(serviceInfo!=null && serviceInfo.getServiceNodes()!=null && serviceInfo.getServiceNodes().size()>0){


            Instance instance = null;

            for(ServiceNode serviceNode:serviceInfo.getServiceNodes()) {

                instance = new Instance();
                instance.setIp(serviceNode.getIp());
                instance.setPort(serviceNode.getPort());
                instance.setHealthy(true);
                instance.setInstanceId(UUID.randomUUID().toString().replace("-",""));

                Map<String,String> metedate = new HashMap<>();
                metedate.put("protocol",serviceNode.getProtocol());
                metedate.put("environment",serviceNode.getEnvironment());


                /**
                 * 合并外部数据
                 */
                for(String key:serviceNode.getMetadata().keySet()){
                    metedate.put(key,serviceNode.getMetadata().get(key));
                }

                instance.setMetadata(metedate);
                try {
                    nameService.registerInstance(serviceInfo.getServiceName(), instance);
                    log.info("nacos {} register success!",serviceInfo.getServiceName());
                }catch (Exception e){
                    log.error("nacos register error!");
                }
            }
            return true;
        }

        return false;

    }


    @Override
    public List<ServiceNode> pullServiceNode(String serviceName) {

        try {
            List<Instance> instances = nameService.getAllInstances(serviceName);


            List<ServiceNode> serviceNodes = new ArrayList<>();

            if(instances!=null && instances.size()>0){

                instances = instances.stream().filter(i->{return i.isHealthy();}).collect(Collectors.toList());
                for(Instance i:instances){
                    serviceNodes.add(convert(i));
                }

            }
            return serviceNodes;

        }catch (Exception e){

        }
        return null;
    }

    private ServiceNode convert(Instance instance){

        ServiceNode serviceNode = new ServiceNode();

        serviceNode.setId(instance.getInstanceId());
        serviceNode.setIp(instance.getIp());
        serviceNode.setPort(instance.getPort());

        Map map = instance.getMetadata();
        serviceNode.setProtocol(map.get("protocol").toString());
        serviceNode.setEnvironment(map.get("environment").toString());
        serviceNode.setMetadata(map);
        return serviceNode;
    }

    class NacosEventListener implements EventListener {

        @Override
        public void onEvent(Event event) {

            synchronized (this) {
                //更新时锁住当前对象。
                NamingEvent namingEvent = (NamingEvent) event;

                String serviceName = NamingUtils.getServiceName(namingEvent.getServiceName());

                //只需要健康的
                List<Instance> instances = namingEvent.getInstances().stream().filter(i->{return i.isHealthy();}).collect(Collectors.toList());

                if (instances != null && instances.size() > 0) {

                    ServiceInfo serviceInfo = null;
                    List<ServiceNode> serviceNodeList = null;
                    if (!serviceInfoMap.containsKey(serviceName)) {

                        serviceInfo = new ServiceInfo();
                        serviceNodeList = new ArrayList<>();
                        serviceInfo.setServiceName(serviceName);
                        serviceInfo.setServiceNodes(serviceNodeList);
                        serviceInfoMap.put(serviceName, serviceInfo);
                    }

                    serviceInfo = serviceInfoMap.get(serviceName);
                    serviceNodeList = serviceInfo.getServiceNodes();

                    serviceNodeList.clear();

                    //每次都获取最新的
                    for (Instance instance : instances) {
                        serviceNodeList.add(convert(instance));
                    }
                }

                log.info("nacos Listener {} success!", serviceName);
            }
        }

    }


    @Override
    public void subscribeAll() {
        this.subscribeService(pullAllService());
    }

    @Override
    public List<String> pullAllService() {
        try {
            ListView<String> servicesOfServer = nameService.getServicesOfServer(1, Integer.MAX_VALUE);

            return servicesOfServer.getData();

        }catch (Exception e){
            log.error("nacos get all service error!");
        }
        return null;
    }
}
